﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="WineItemFactory.cs" company="Simon Carpentier">
//   Microsoft Reciprocal License (Ms-RL)
// </copyright>
// <summary>
//   Defines the WineItemFactory type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace VinoCellar
{
    using System;
    using System.Diagnostics;
    using System.Globalization;
    using System.Linq;
    using System.Net;
    using System.Text.RegularExpressions;

    using VinoCellar.Model;

    public class WineItemFactory
    {
        /// <summary>
        /// URL pour envoyer une recherche au site web de la SAQ
        /// </summary>
        private const string SaqSearchUrl =
            "http://www.saq.com/webapp/wcs/stores/servlet/CatalogSearchResultView?storeId=10001&catalogId=10001&langId=-2&pageSize=10&beginIndex=0&resultCatEntryType=2&searchType=100&tri=RechercheUCIProdDescAttributeInfo&sensTri=AscOperator&viewTaskName=SAQCatalogSearchResultView&searchTerm={0}";

        /// <summary>
        /// Regex du nom du vin
        /// </summary>
        private const string WineNameRegex = @"<meta name=""WT\.cg_n"" content=""([^""]*)"">";

        /// <summary>
        /// Regex de la catégorie du vin
        /// </summary>
        private const string WineCategoryRegex = @"<td class=""fiche_libelles"">Catégorie :</td>[""\s]*<td>([^<]*)</td>";

        /// <summary>
        /// Regex du pays du vin
        /// </summary>
        private const string WineCountryRegex =
            @"<td class=""fiche_libelles"">[\s]*Pays :[\s]*</td>[\s]*<td>([^<]*)</td>";

        /// <summary>
        /// Regex de la région du vin
        /// </summary>
        private const string WineRegionRegex =
            @"<td class=""fiche_libelles"">[\s]*Région :[\s]*</td>[\s]*<td>([^<]*)</td>";

        /// <summary>
        /// Regex de la sous-région du vin
        /// </summary>
        private const string WineSubregionRegex =
            @"<td class=""fiche_libelles"">[\s]*Sous région :[\s]*</td>[\s]*<td>([^<]*)</td>";

        /// <summary>
        /// Regex de l'appellation du vin
        /// </summary>
        private const string WineAppellationRegex =
            @"<td class=""fiche_libelles"">[\s]*Appellation :[\s]*</td>[\s]*<td>([^<]*)</td>";

        /// <summary>
        /// Regex du prix de la bouteille
        /// </summary>
        private const string WinePriceRegex = @"<span class=""price"">([^<]*)&nbsp;\$</span>";

        /// <summary>
        /// Regex de l'image de la bouteille
        /// </summary>
        private const string WinePictureRegex = "<table width=\"100%\" border=\"0\" class=\"fiche_introduction transparent\">[^<]*<tr>[^<]*<td width=\"140\">[^<]*<img src=\"([^\"]*)\"";

        /// <summary>
        /// HTML du site de la SAQ
        /// </summary>
        private string data;

        /// <summary>
        /// Évènement pour savoir quand les informations sont chargés
        /// </summary>
        public event FetcherLoadedDelegate Loaded;

        public delegate void FetcherLoadedDelegate(WineItem wineItem, bool alreadyExisting);

        private string upc;

        public WineItem GetWineItem(int id)
        {
            this.WineItem = App.ViewModel.AllWineItems.SingleOrDefault(x => x.WineItemId == id);
            if (this.WineItem != null)
            {
                IsExisting = true;
                IsLoaded = true;
                Error = string.Empty;
                if (Loaded != null)
                    Loaded(this.WineItem, IsExisting);

                return this.WineItem;
            }
            else
            {
                throw new Exception(string.Format("Could not find wine Item ID {0}", id));
            }
        }

        public void GetWineItem(string upc)
        {
            // On va commencer par aller voir s'il existe déjà
            this.WineItem = App.ViewModel.AllWineItems.SingleOrDefault(x => x.WineUpc == upc);
            if (this.WineItem == null)
            {
                // Il n'existe pas, on va le créer
                this.upc = upc;
                var webClient = new WebClient();
                webClient.DownloadStringCompleted +=
                    new DownloadStringCompletedEventHandler(this.webClient_DownloadStringCompleted);
                try
                {
                    webClient.DownloadStringAsync(new Uri(string.Format(SaqSearchUrl, upc)));
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                    throw;
                }
            }
            else
            {
                // Il existe déjà, on fait juste le retourner
                IsLoaded = true;
                IsExisting = true;
                Error = string.Empty;
                if (Loaded != null)
                    this.Loaded(this.WineItem, IsExisting);
            }
        }

        public bool IsLoaded { get; private set; }

        public bool IsExisting { get; private set; }

        public string Error { get; private set; }

        public WineItem WineItem { get; private set; }

        private void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            this.data = e.Result;

            try
            {

                this.WineItem = new WineItem
                    {
                        WineName = ApplyRegex(WineNameRegex),
                        WineCategory = ApplyRegex(WineCategoryRegex),
                        WineAppellation = ApplyRegex(WineAppellationRegex),
                        WineCountry = ApplyRegex(WineCountryRegex),
                        WinePrice = double.Parse(ApplyRegex(WinePriceRegex), new CultureInfo("fr-CA").NumberFormat),
                        WineRegion = ApplyRegex(WineRegionRegex),
                        WineSubregion = ApplyRegex(WineSubregionRegex),
                        WinePictureUrl = ApplyRegex(WinePictureRegex),
                        WineUpc = upc
                    };

                IsLoaded = true;
                IsExisting = false;
                Error = string.Empty;
            }
            catch (Exception ex)
            {
                Error = ex.Message;
            }

            if (Loaded != null)
                Loaded(this.WineItem, IsExisting);
        }

        /// <summary>
        /// Applique un regex aux données
        /// </summary>
        /// <param name="regex"></param>
        /// <returns></returns>
        private string ApplyRegex(string regex)
        {
            var result = string.Empty;
            try
            {
                var regexObj = new Regex(regex, RegexOptions.IgnoreCase);
                var matchResults = regexObj.Match(this.data);
                while (matchResults.Success)
                {
                    for (int i = 1; i < matchResults.Groups.Count; i++)
                    {
                        Group groupObj = matchResults.Groups[i];
                        if (groupObj.Success)
                        {
                            result = matchResults.Groups[1].Captures[0].Value;
                        }
                    }

                    matchResults = matchResults.NextMatch();
                }
            }
            catch (ArgumentException ex)
            {
                // Syntax error in the regular expression
            }

            return HttpUtility.HtmlDecode(result);
        }
    }
}